package cn.seqdata.jpa;

import java.util.Comparator;

import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;

import org.apache.commons.lang3.BooleanUtils;
import org.joda.time.DateTime;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.domain.Auditable;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties({ "createdBy", "createdDate", "lastModifiedBy", "lastModifiedDate" })
public abstract class JpaAuditableObject extends JpaNamed<Long>
		implements Auditable<Long, Long>, Comparable<JpaAuditableObject> {
	private static final long serialVersionUID = 1L;

	private Boolean disable;
	private Integer orderNo;
	private Long createdBy;
	private DateTime createdDate;
	private Long lastModifiedBy;
	private DateTime lastModifiedDate;

	public JpaAuditableObject() {
		super();
	}

	public JpaAuditableObject(Long id) {
		super(id);
	}

	public JpaAuditableObject(Long id, String name) {
		super(id, name);
	}

	@Column(name = "disable")
	public Boolean getDisable() {
		return BooleanUtils.isTrue(disable);
	}

	public void setDisable(Boolean disable) {
		this.disable = disable;
	}

	@Column(name = "order_no")
	public Integer getOrderNo() {
		return orderNo;
	}

	public void setOrderNo(Integer orderNo) {
		this.orderNo = orderNo;
	}

	@Override
	@CreatedBy
	@Column(name = "created_by", updatable = false)
	public Long getCreatedBy() {
		return this.createdBy;
	}

	@Override
	public void setCreatedBy(Long createdBy) {
		this.createdBy = createdBy;
	}

	@Override
	@CreatedDate
	@Column(name = "created_date", updatable = false)
	@Convert(converter = cn.seqdata.jpa.converter.DateTimeConverter.class)
	public DateTime getCreatedDate() {
		return this.createdDate;
	}

	@Override
	public void setCreatedDate(DateTime createdDate) {
		this.createdDate = createdDate;
	}

	@Override
	@LastModifiedBy
	@Column(name = "last_modified_by", insertable = false)
	public Long getLastModifiedBy() {
		return this.lastModifiedBy;
	}

	@Override
	public void setLastModifiedBy(Long lastModifiedBy) {
		this.lastModifiedBy = lastModifiedBy;
	}

	@Override
	@LastModifiedDate
	@Column(name = "last_modified_date", insertable = false)
	@Convert(converter = cn.seqdata.jpa.converter.DateTimeConverter.class)
	public DateTime getLastModifiedDate() {
		return this.lastModifiedDate;
	}

	@Override
	public void setLastModifiedDate(DateTime lastModifiedDate) {
		this.lastModifiedDate = lastModifiedDate;
	}

	@Override
	public String toString() {
		return String.format("%s[%d]:%s", getClass().getSimpleName(), id, getName());
	}

	@Override
	public int hashCode() {
		return ((id == null) ? 0 : id.hashCode());
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;

		JpaAuditableObject other = (JpaAuditableObject) obj;
		if (null != id && null != other.id)
			return id.equals(other.id);
		else
			return (null == id && null == other.id);
	}

	@Override
	public int compareTo(JpaAuditableObject o) {
		/** 排序比较器 orderNo / null / id */
		final Comparator<? super JpaAuditableObject> comparator = Comparator
			.comparing(JpaAuditableObject::getOrderNo, Comparator.nullsLast(Comparator.comparingInt(Integer::intValue)))
			.thenComparing(JpaAuditableObject::getName, Comparator.nullsFirst(PinYinComparator.instance));

		return comparator.compare(this, o);
	}
}
